﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using ATEC.ATDataCoreNET;
using ATEC.GeometryNET;
using ATSceneExample;
using System.Windows.Forms;
using System.IO;

namespace LevelExample
{
    /// <summary>
    /// 功能：图层管理与操作工具类
    /// 描述：提供对玄镜图形平台中的图层操作，包括创建图层、设置图层属性以及在不同图层上绘制曲线等功能。
    /// 关键类及说明：
    /// - **FileLevelCache**: 管理当前工程的图层缓存，用于创建、查找图层。
    /// - **LevelHandle**: 图层句柄，用于访问图层属性和状态。
    /// - **EditLevelHandle**: 可编辑的图层句柄，支持设置图层颜色和其他属性。
    /// - **CurveSet**: 表示曲线集合，用于在场景中创建几何图形。
    /// - **ObjectPropertiesSetter**: 提供设置对象属性（如图层、颜色）的功能。
    /// 注意：
    /// - 确保工程和场景有效后再进行图层和对象操作。
    /// - 曲线绘制时需指定图层以区分内容。
    /// </summary>
    public class LevelMethod
    {
        /// <summary>
        /// 红色图层的名称。
        /// </summary>
        private const string redLevelName = "RedLevel";

        /// <summary>
        /// 蓝色图层的名称。
        /// </summary>
        private const string blueLevelName = "BlueLevel";

        /// <summary>
        /// 功能：创建预定义的图层
        /// 描述：分别创建红色和蓝色两个图层。
        /// </summary>
        public static void CreateLevels()
        {
            CreateLevelByName(redLevelName); // 创建红色图层。
            CreateLevelByName(blueLevelName); // 创建蓝色图层。
        }

        /// <summary>
        /// 功能：根据名称创建图层
        /// 描述：检查图层是否已存在，若不存在则创建并设置对应的颜色。
        /// <param name="levelName">图层名称。</param>
        /// </summary>
        public static void CreateLevelByName(string levelName)
        {
            ATProject activeProject = ATEC.ATCore.Session.Entity.GetActiveATProject(); // 获取当前活跃的 AT 工程。
            FileLevelCache fileLevelCache = activeProject.GetLevelCache(); // 获取工程的图层缓存。
            LevelHandle level = fileLevelCache.GetLevelByName(levelName); // 根据名称查找图层。

            if (!level.IsValid) // 如果图层无效（不存在）。
            {
                EditLevelHandle edLevel = fileLevelCache.CreateLevel(levelName); // 创建新图层。

                // 设置图层颜色。
                LevelDefinitionColor levelColor = new LevelDefinitionColor(0, activeProject); // 默认为白色。
                if (levelName == redLevelName)
                    levelColor = new LevelDefinitionColor(3, activeProject); // 设置为红色。
                else if (levelName == blueLevelName)
                    levelColor = new LevelDefinitionColor(1, activeProject); // 设置为蓝色。

                edLevel.SetByLevelColor(levelColor); // 应用颜色设置。
                fileLevelCache.Write(); // 保存图层缓存的更改。

                MessageBox.Show("创建图层成功：" + levelName); // 显示成功消息。
            }
            else
            {
                MessageBox.Show("图层已存在：" + levelName); // 提示图层已存在。
            }
        }

        /// <summary>
        /// 功能：在不同图层上绘制曲线
        /// 描述：分别在红色和蓝色图层上绘制预定义的曲线。
        /// </summary>
        public static void DrawCurveOnLevels()
        {
            DrawCurveOnLevel(redLevelName); // 在红色图层上绘制曲线。
            DrawCurveOnLevel(blueLevelName); // 在蓝色图层上绘制曲线。
        }

        /// <summary>
        /// 功能：在指定图层上绘制曲线
        /// 描述：根据图层名称生成曲线，并将其添加到指定图层中。
        /// <param name="levelName">图层名称。</param>
        /// </summary>
        public static void DrawCurveOnLevel(string levelName)
        {
            ATProject activeProject = ATEC.ATCore.Session.Entity.GetActiveATProject(); // 获取当前活跃的 AT 工程。
            FileLevelCache fileLevelCache = activeProject.GetLevelCache(); // 获取工程的图层缓存。
            LevelHandle level = fileLevelCache.GetLevelByName(levelName); // 根据名称查找图层。
            double offset = 0; // 初始化偏移量。
            if (levelName.Equals(blueLevelName))
                offset = 5; // 如果是蓝色图层，设置偏移量。

            // 创建曲线的点集。
            XPoint3d pt1 = XPoint3d.FromXYZ(0 + offset, 10, 10); // 点1。
            XPoint3d pt2 = XPoint3d.FromXYZ(0 + offset, 10, -10); // 点2。
            XPoint3d pt3 = XPoint3d.FromXYZ(0 + offset, -10, -10); // 点3。
            XPoint3d pt4 = XPoint3d.FromXYZ(0 + offset, -10, 10); // 点4。
            List<XPoint3d> pts = new List<ATEC.GeometryNET.XPoint3d> { pt1, pt2, pt3, pt4, pt1 }; // 形成闭合曲线。
            CurveSet tempCurveSet = CurveSet.CreateLinear(pts, CurveSet.BoundaryType.Outer, true); // 创建线性曲线集合。

            ATScene scene = ATSceneMethod.GetATScene(activeProject, "三维模型空间"); // 获取目标场景。
            if (!scene.IsValid())
                return; // 如果场景无效，退出。

            // 设置对象的图层信息并添加到场景。
            ATEC.ATDataCoreNET.ATObjects.ATObject obj = ATEC.ATDataCoreNET.ATObjects.GeometryToATObject.ToObject(scene.GetATScene(), tempCurveSet, null); // 转换为 ATObject。
            SetObjectLevelInfo(obj, levelName); // 设置对象的图层信息。
            obj.AddToScene(); // 将对象添加到场景。
        }

        /// <summary>
        /// 功能：根据图层名称获取颜色编号
        /// 描述：返回图层对应的颜色编号。
        /// <param name="levelName">图层名称。</param>
        /// <returns>颜色编号。</returns>
        /// </summary>
        public static uint GetColorIndexByLevelName(string levelName)
        {
            uint colorIndex = 0; // 默认颜色编号。
            if (levelName == redLevelName)
                colorIndex = 3; // 红色编号。
            else if (levelName == blueLevelName)
                colorIndex = 1; // 蓝色编号。

            return colorIndex; // 返回颜色编号。
        }

        /// <summary>
        /// 功能：设置对象的图层信息
        /// 描述：为对象分配图层和颜色等属性。
        /// <param name="obj">目标对象。</param>
        /// <param name="levelName">图层名称。</param>
        /// </summary>
        public static void SetObjectLevelInfo(ATEC.ATDataCoreNET.ATObjects.ATObject obj, string levelName)
        {
            if (!obj.IsValid) // 检查对象是否有效。
                return; // 如果无效，退出。

            FileLevelCache levelCache = obj.ATScene.GetATProject().GetLevelCache(); // 获取对象所属工程的图层缓存。
            LevelHandle level = levelCache.GetLevelByName(levelName); // 查找目标图层。
            if (LevelCacheErrorCode.None != level.Status) // 如果图层状态异常。
            {
                string error = "未找到图层" + levelName + "已启用默认图层!"; // 提示错误。
                SSDPNET.ATOutputFuncs.OutputError(error); // 输出错误信息。
                return; // 退出操作。
            }

            ObjectPropertiesSetter eps = new ObjectPropertiesSetter(); // 创建属性设置器。
            eps.SetLevel(level.LevelId); // 设置对象所属图层。
            eps.SetColor(GetColorIndexByLevelName(levelName)); // 设置对象颜色。
            eps.Apply(obj); // 应用设置到对象。
        }

        /// <summary>
        /// 功能：删除图层
        /// 描述：从当前工程中删除指定的图层，如果图层正在使用则提示用户先清理图层内容。
        /// 关键类及说明：
        /// - **ATProject**: 表示当前活动的工程，提供工程相关操作的入口。
        /// - **FileLevelCache**: 图层缓存，管理当前工程中的所有图层。
        /// - **LevelHandle**: 图层句柄，代表工程中的单个图层。
        /// 注意：
        /// - 如果图层正在使用，需要清空图层上的所有对象后再尝试删除。
        /// - 调用 `fileLevelCache.Write()` 确保图层变更被保存到工程文件。
        /// </summary>
        public static void DeleteLevel()
        {
            // 待删除的图层列表，包括红色和蓝色图层
            List<string> lstToDelete = new List<string> { redLevelName, blueLevelName };

            // 获取当前工程和其图层缓存
            ATProject activeProject = ATEC.ATCore.Session.Entity.GetActiveATProject(); // 获取当前活跃工程
            FileLevelCache fileLevelCache = activeProject.GetLevelCache(); // 获取工程中的图层缓存

            // 遍历所有图层句柄
            foreach (LevelHandle h in fileLevelCache.GetHandles())
            {
                // 如果当前图层不在删除列表中，则跳过
                if (!lstToDelete.Contains(h.Name)) { continue; }

                // 保存图层名称以便输出提示信息
                string nm = h.Name;

                // 尝试移除图层
                LevelCacheErrorCode errorCode = fileLevelCache.RemoveLevel(null /* h */, h); // 删除图层

                // 根据删除结果显示不同的消息
                if (LevelCacheErrorCode.None == errorCode)
                {
                    // 图层删除成功
                    MessageBox.Show(nm + "图层删除成功!\n" + "\n 点击继续.");
                }
                else if (errorCode == LevelCacheErrorCode.LevelIsUsed)
                {
                    // 图层正在使用，无法删除
                    MessageBox.Show(nm + "正在使用，请删除图层上所有对象，再删除图层");
                }
                else
                {
                    // 其他原因导致删除失败
                    MessageBox.Show(nm + "删除失败，错误代码：" + errorCode.ToString());
                }
            }

            // 保存图层变更到工程
            fileLevelCache.Write(); // 写入工程以保存对图层的变更
        }

        /// <summary>
        /// 功能：从外部数据库拷贝图层到当前数据库
        /// 描述：从外部工程文件中复制所有图层到当前活动的工程中，以实现图层共享或数据整合。
        /// 关键类及说明：
        /// - **OpenFileDialog**: 提供文件选择窗口，用于指定外部工程文件。
        /// - **ATProject**: 表示工程，支持只读或读写模式加载。
        /// - **FileLevelCache**: 管理图层缓存，用于图层的读取和写入操作。
        /// 注意：
        /// - 确保外部数据库文件路径有效且可以访问。
        /// - 调用 `toDbFileLevelCahe.Write()` 和 `toDb.ProcessChanges()` 确保变更生效。
        /// </summary>
        public static void CopyLevel()
        {
            // 打开文件选择对话框以指定外部数据库文件
            System.Windows.Forms.OpenFileDialog dialog = new System.Windows.Forms.OpenFileDialog();
            dialog.Title = "请选择要导入的图层文件";
            dialog.ShowDialog(); // 显示对话框

            // 打开选定的数据库文件
            ATDoc doc = ATDoc.CreateForLocalFile(dialog.FileName); // 创建文档对象
            if (doc == null) // 如果文档对象无效，则退出
            {
                return;
            }

            // 加载外部数据库工程
            ATProject fromDb = ATProject.Create(doc, ATProjectOpenMode.ReadOnly).ATProject; // 打开只读模式
            if (!fromDb.IsLoaded) // 检查工程是否已加载
            {
                StatusInt openForWriteStatus = StatusInt.Error;
                ATProjectStatus status = fromDb.LoadATProject(out openForWriteStatus); // 加载工程
            }

            // 获取当前活动工程及其图层缓存
            ATProject toDb = ATEC.ATCore.Session.Entity.GetActiveATProject(); // 获取当前工程
            FileLevelCache toDbFileLevelCahe = toDb.GetLevelCache(); // 当前工程的图层缓存
            FileLevelCache fromDbFileLevelCahe = fromDb.GetLevelCache(); // 外部工程的图层缓存

            // 遍历外部工程中的所有图层
            foreach (var level in fromDbFileLevelCahe.GetHandles())
            {
                // 复制图层到当前工程
                var levelCopied = toDbFileLevelCahe.CopyLevel(level); // 拷贝图层
                if (levelCopied == null) // 如果拷贝失败，则退出
                    return;
            }

            // 写入图层变更并保存到当前工程
            LevelCacheErrorCode code = toDbFileLevelCahe.Write(); // 保存图层
            toDb.ProcessChanges(ATSaveReason.ApplicationInitiated); // 提交更改
        }
    }
}
